Functional Market 1.0.2

function pointers


If there is a conflict between the subject and the skeleton or moulinette, the subject is always right.
However, please report any inconsistencies to your assistant.

Submissions

Repository structure
At the end, your git repo must follow this architecture:
epita-prepa-computer-science-prog-104-p-03-2030-firstname.lastname
├── functional_market
│   ├── Fundamentals
│   │   ├── calculator.c
│   │   ├── calculator.h
│   │   ├── crepe_stream.c
│   │   ├── crepe_stream.h
│   │   ├── intro.c
│   │   ├── intro.h
│   │   ├── toolbox.c
│   │   └── toolbox.h
│   └── Proficiencies
│       ├── list.c
│       ├── list.h
│       ├── visitor.c
│       └── visitor.h
├── .gitignore
└── README

Do not forget to check the following requirements before submitting your work:
  • You shall obviously replace firstname.lastname with your login.
  • The .gitignore file is mandatory.
  • Remove all personal tests from your code, except those from the Tests folder.
  • The given prototypes must be strictly respected.
  • The code MUST compile! Otherwise you will not receive a grade.

.gitignore example
Here is an example of a .gitignore file:
*.a
*.lib
*.o
*.obj
*.out

.idea/
*~
*.DotSettings.user

This needs to be setup before the first submission!

Introduction


In this practical, you will learn about how to use Function pointers.
You will need to have a thorough understanding of arrays, and trees.
You will also be using notions from previous practicals such as linked lists.
Here's a reminder: if you have trouble understanding something, just ask your assistants by making a ticker on discord!

Authorized includes
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Lore
The market will open soon! However, it's not ready, the villager need your help!

Lore
A villager needs your help at the crepe stand, get your tools and help them!



fundamentals/intro.c


Lore
Before being able to help anyone, you need to learn how to use your tools.

To start off, you have to implement a function that returns the result of passing its input to a function pointer computer.

Prototype(s)
int compute(int input, int (*executor)(int));

Code example(s)
int next(int n)
{
    return n + 1;
}

#include <stdio.h>
int main(void)
{
    int n = 3;
    printf("compute(%d, &next) = %d\n", n, compute(n, &next));
}

Output
compute(3, &next) = 4

Now, you have to return a function pointer depending on the name.
When this function pointer is executed, it needs to print one of the following lines depending on the name given.

Output
# name = "Isabelle":
Hello Isabelle!

# name = "Tom Nook":
Hi Tom Nook.

# name = "Blathers":
Good night Blathers!

# name = "Mr. Resetti":
How are you doing Mr. Resetti?

# Anything else (including NULL):
I don't know you!

Warning(s)
Don't forget to add a newline at the end!

Hint(s)
That means you will need to create multiple auxiliary functions. Their names do not matter, they only need to follow the right signature.

Prototype(s)
void (*greet(char *name))(void);

Information
Understanding the signature of this function is part of the exercise.

Code example(s)
int main(int argc, char *argv[])
{
    (void)argc;
    (*greet(argv[1]))();
}

Output
$ ./greet Isabelle
Hello Isabelle!
$ ./greet Toto
I don't know you!



fundamentals/calculator.c


Lore
You shouldn't forget your trusty calculator!

Danger(s)
For this function, you MUST NOT use any if, for, while or switch.
Instead, you MUST use a lookup table, that store multiple functions.
You SHOULD use a typedef for functions that take two integers and return an integer.
If you do, you MUST name it operator and put it into your calculator.h.

For this function, you should return the result of the operation between a and b depending on op.

calculator.h
enum operation
{
    ADD,
    SUB,
    MUL,
    DIV,
    MOD,
};

Prototype(s)
int calculator(int a, int b, enum operation op);

Hint(s)
You do not need to care about invalid operations such as division by zero, and they will not be tested.

Code example(s)
#include <stdio.h>
int main(void)
{
    int a = 4;
    int b = 6;
    enum operation op = ADD;
    printf("calculator(%d, %d, %d) = %d\n", a, b, op, calculator(a, b, op));
}

Output
calculator(4, 6, 0) = 10



fundamentals/toolbox.c


Lore
One last step before you go to the market: put all your tools in the toolbox.

Information
Here are structures as well as typedefs you will be using for the following exercises.
They are already present in the toolbox.h header file.

Each typedef is explained in its associated function.
There will also be examples provided to better understand how they work.

In an array, only data itself is allocated on the heap, not its elements.
A NULL array is treated as an empty array, not an error.

The reason the data of an array is a void * is to allow any type of element,
such as integers, strings and other structs.
To modify its content, it is usually cast as a char * to have an easy access to each byte.
Here is a simple example on how to access an element of the array:

Code example(s)
char *data = arr->data;
char *second_element = data + arr->elem_size;
char *fifth_element = data + 4 * arr->elem_size; // Don't forget array indexes are zero-based

toolbox.h
#include <stddef.h>

typedef int (*comparator)(void *, void *);
typedef void (*mapper)(void *, void *);
typedef int (*predicate)(void *);
typedef void *(*reducer)(void *, void *);
typedef void (*acceptor)(void *);

struct array
{
    void *data;
    size_t len;
    size_t elem_size;
};

This function applies f on every element of arr.

Hint(s)
An acceptor is a function that takes a pointer to an element of the array.

Prototype(s)
void foreach(struct array *arr, acceptor f);

Code example(s)
#include <stdio.h>
#include <stdlib.h>

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(&arr, (acceptor)&print_int);

    free(arr.data);
}

Output
0
1
2
3

This function returns arr sorted according to f.

Hint(s)
A comparator is a function that takes two pointers to elements of the array,
and returns a value :

- equal to 0 if they are equal
- less than 0 if the first is less than the second
- greater than 0 if the first is greater than the second

Danger(s)
Be careful, only the content of arr must change, you MUST return arr.

Prototype(s)
struct array *sort(struct array *arr, comparator f);

Code example(s)
#include <stdio.h>
#include <stdlib.h>

int reverse(int *a, int *b)
{
    return *b - *a;
}

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(sort(&arr, (comparator)&reverse), (acceptor)&print_int);

    free(arr.data);
}

Output
3
2
1
0

This function returns arr mapped according to f.

Hint(s)
A mapper is a function that takes two pointers.

The first is the destination, and the second is the source.

Information
To map an array means creating a new array by applying a function on each of the elements.
The types of the elements in the array before and after mapping CAN be different.

Danger(s)
Be careful, only the content of arr must change, you MUST return arr.
You will need to reallocate a new arr->data, and free the previous one.

Hint(s)
output_size is the size of an element after mapping.
Don't forget to update arr with it!

Prototype(s)
struct array *map(struct array *arr, size_t output_size, mapper f);

Code example(s)
#include <stdio.h>
#include <stdlib.h>

void next(double *res, int *n)
{
    *res = *n + 1;
}

void print_double(double *n)
{
    printf("%.1lf\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(map(&arr, sizeof(double), (mapper)&next), (acceptor)&print_double);

    free(arr.data);
}

Output
1.0
2.0
3.0
4.0

This function returns arr filtered according to if f is true.

Hint(s)
A predicate is a function that takes a pointer to an element of the array, and returns a value:
- equal to 0 if the predicate is false
- different from 0 if the predicate is true

Danger(s)
Be careful, only the content of arr must change, you MUST return arr.

Prototype(s)
struct array *filter(struct array *arr, predicate f);

Code example(s)
#include <stdio.h>
#include <stdlib.h>

int odd(int *n)
{
    return *n % 2;
}

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    foreach(filter(&arr, (predicate)&odd), (acceptor)&print_int);

    free(arr.data);
}

Output
1
3

This function returns the result of arr reduced by f.

Hint(s)
A reducer is a function that takes two pointers.

The first is the destination, and the second is the source.

It also returns the destination.

Prototype(s)
void *reduce(struct array *arr, void *start_value, reducer f);

Code example(s)
#include <stdio.h>
#include <stdlib.h>

int *add(int *res, int *n)
{
    *res += *n;
    return res;
}

void print_int(int *n)
{
    printf("%d\n", *n);
}

int main(void)
{
    struct array arr = {
        .data = calloc(4, sizeof(int)),
        .len = 4,
        .elem_size = sizeof(int),
    };

    int *data = arr.data;
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;

    int res = 0;
    reduce(&arr, &res, (reducer)&add);
    printf("%d\n", res);

    free(arr.data);
}

Output
6



fundamentals/crepe_stream.c


Lore
Someone needs you at the crepe stand, they need you to organize the menu.

Danger(s)
For the next part, you MUST use your previous functions.
The moulinette will use its own, but if you haven't done them,
you won't be able to test on your computer.

It is up to you to use the correct one. It will be tested.

crepe_stream.h
enum dough
{
    WHEAT,
    BUCKWHEAT,
};

enum topping
{
    NOTHING,

    // Sweet
    SUGAR,
    CHOCOLATE,
    WHIPPED_CREAM,

    // Savory
    CHEESE,
    MEAT,
    EGG,
};

struct crepe
{
    char *name;
    enum dough dough;
    enum topping inside;
    enum topping outside;
    int price;
};

Hint(s)
You will need to make multiple auxiliary functions, but the the main functions only need a few lines.

This function prints all crepes in the array according to the following format,
with all enumerations in lowercase and with any character '_' replaced by a space :

Output
<name>: $<price>
- Made out of <dough>
- Contains <inside topping> with <outside topping> on top

Prototype(s)
void print_menu(struct array *arr);

Code example(s)
#include <stdlib.h>

int main(void)
{
    struct array arr = {
        .elem_size = sizeof(struct crepe),
        .len = 4,
        .data = calloc(4, sizeof(struct crepe)),
    };
    struct crepe *data = arr.data;
    data[0] = (struct crepe){
        .name = "Dairy",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = EGG,
        .price = 5,
    };
    data[1] = (struct crepe){
        .name = "Raclette",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = MEAT,
        .price = 8,
    };
    data[2] = (struct crepe){
        .name = "Choco",
        .dough = WHEAT,
        .inside = CHOCOLATE,
        .outside = WHIPPED_CREAM,
        .price = 6,
    };
    data[3] = (struct crepe){
        .name = "Sugary",
        .dough = WHEAT,
        .inside = SUGAR,
        .outside = NOTHING,
        .price = 7,
    };

    print_menu(&arr);

    free(arr.data);
}

Output
Dairy: $5
- Made out of buckwheat
- Contains cheese with egg on top
Raclette: $8
- Made out of buckwheat
- Contains cheese with meat on top
Choco: $6
- Made out of wheat
- Contains chocolate with whipped cream on top
Sugary: $7
- Made out of wheat
- Contains sugar with nothing on top

This function returns the array of crepes sorted by prices

Even prices should come first in ascending order, then odd prices in descending order.

Prototype(s)
struct array *sort_by_prices(struct array *arr);

Code example(s)
#include <stdlib.h>

int main(void)
{
    struct array arr = {
        .elem_size = sizeof(struct crepe),
        .len = 4,
        .data = calloc(4, sizeof(struct crepe)),
    };
    struct crepe *data = arr.data;
    data[0] = (struct crepe){
        .name = "Dairy",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = EGG,
        .price = 5,
    };
    data[1] = (struct crepe){
        .name = "Raclette",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = MEAT,
        .price = 8,
    };
    data[2] = (struct crepe){
        .name = "Choco",
        .dough = WHEAT,
        .inside = CHOCOLATE,
        .outside = WHIPPED_CREAM,
        .price = 6,
    };
    data[3] = (struct crepe){
        .name = "Sugary",
        .dough = WHEAT,
        .inside = SUGAR,
        .outside = NOTHING,
        .price = 7,
    };

    print_menu(sort_by_prices(&arr));

    free(arr.data);
}

Output
Choco: $6
- Made out of wheat
- Contains chocolate with whipped cream on top
Raclette: $8
- Made out of buckwheat
- Contains cheese with meat on top
Sugary: $7
- Made out of wheat
- Contains sugar with nothing on top
Dairy: $5
- Made out of buckwheat
- Contains cheese with egg on top

This function returns the names of the crepes in the array of crepes

Prototype(s)
struct array *names(struct array *arr);

Code example(s)
#include <stdlib.h>

void print_string(char **str)
{
    puts(*str);
}

int main(void)
{
    struct array arr = {
        .elem_size = sizeof(struct crepe),
        .len = 4,
        .data = calloc(4, sizeof(struct crepe)),
    };
    struct crepe *data = arr.data;
    data[0] = (struct crepe){
        .name = "Dairy",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = EGG,
        .price = 5,
    };
    data[1] = (struct crepe){
        .name = "Raclette",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = MEAT,
        .price = 8,
    };
    data[2] = (struct crepe){
        .name = "Choco",
        .dough = WHEAT,
        .inside = CHOCOLATE,
        .outside = WHIPPED_CREAM,
        .price = 6,
    };
    data[3] = (struct crepe){
        .name = "Sugary",
        .dough = WHEAT,
        .inside = SUGAR,
        .outside = NOTHING,
        .price = 7,
    };

    foreach(names(&arr), (acceptor)&print_string);

    free(arr.data);
}

Output
Dairy
Raclette
Choco
Sugary

This function returns the array of crepes containing only crepes that do not have any meat.

Prototype(s)
struct array *vegetarian(struct array *arr);

Code example(s)
#include <stdlib.h>

int main(void)
{
    struct array arr = {
        .elem_size = sizeof(struct crepe),
        .len = 4,
        .data = calloc(4, sizeof(struct crepe)),
    };
    struct crepe *data = arr.data;
    data[0] = (struct crepe){
        .name = "Dairy",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = EGG,
        .price = 5,
    };
    data[1] = (struct crepe){
        .name = "Raclette",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = MEAT,
        .price = 8,
    };
    data[2] = (struct crepe){
        .name = "Choco",
        .dough = WHEAT,
        .inside = CHOCOLATE,
        .outside = WHIPPED_CREAM,
        .price = 6,
    };
    data[3] = (struct crepe){
        .name = "Sugary",
        .dough = WHEAT,
        .inside = SUGAR,
        .outside = NOTHING,
        .price = 7,
    };

    print_menu(vegetarian(&arr));

    free(arr.data);
}

Output
Dairy: $5
- Made out of buckwheat
- Contains cheese with egg on top
Choco: $6
- Made out of wheat
- Contains chocolate with whipped cream on top
Sugary: $7
- Made out of wheat
- Contains sugar with nothing on top

This function returns the total price of the crepes in the array.

Prototype(s)
int total_price(struct array *arr);

Code example(s)
#include <stdlib.h>

int main(void)
{
    struct array arr = {
        .elem_size = sizeof(struct crepe),
        .len = 4,
        .data = calloc(4, sizeof(struct crepe)),
    };
    struct crepe *data = arr.data;
    data[0] = (struct crepe){
        .name = "Dairy",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = EGG,
        .price = 5,
    };
    data[1] = (struct crepe){
        .name = "Raclette",
        .dough = BUCKWHEAT,
        .inside = CHEESE,
        .outside = MEAT,
        .price = 8,
    };
    data[2] = (struct crepe){
        .name = "Choco",
        .dough = WHEAT,
        .inside = CHOCOLATE,
        .outside = WHIPPED_CREAM,
        .price = 6,
    };
    data[3] = (struct crepe){
        .name = "Sugary",
        .dough = WHEAT,
        .inside = SUGAR,
        .outside = NOTHING,
        .price = 7,
    };

    printf("%d\n", total_price(&arr));

    free(arr.data);
}

Output
26


Information
In this part, you will be manipulating simply linked generic lists and binary trees.



proficiencies/list.c


Information
NULL is considered an empty list.

list.h
typedef void (*acceptor)(void*);

struct list
{
    void *data;
    struct list *next;
    acceptor print;
    acceptor free;
};

This function adds a new element at the front of the linked list.

If l is NULL, don't do anything and return.

Prototype(s)
void push_front(struct list **l, void *data, acceptor p, acceptor f);

This function removes the element at the front of the linked list.
There shouldn't be any memory leaks.

If l is NULL or empty, don't do anything and return.

Prototype(s)
void pop_front(struct list **l);

Code example(s)
void do_nothing(void *n)
{
    (void)n;
}

void print_long(void *n)
{
    printf("%ld", (long)n);
}

void print_int(int *n)
{
    printf("%d", *n);
}

int main(void)
{
    struct list *l = NULL;
    push_front(&l, (void *)18, &print_long, &do_nothing);
    int *on_heap = calloc(1, sizeof(int));
    *on_heap = 42;
    push_front(&l, on_heap, (acceptor)&print_int, &free);
    int on_stack = 4;
    push_front(&l, &on_stack, (acceptor)&print_int, &do_nothing);
    // print_list(l);
    pop_front(&l);
    pop_front(&l);
    pop_front(&l);
}

Output
// Nothing

This function prints every element, separated by " -> ".
The output must always be terminated by a newline.

Prototype(s)
void print_list(struct list *l);

Code example(s)
void do_nothing(void *n)
{
    (void)n;
}

void print_long(void *n)
{
    printf("%ld", (long)n);
}

void print_int(int *n)
{
    printf("%d", *n);
}

int main(void)
{
    struct list *l = NULL;
    push_front(&l, (void *)18, &print_long, &do_nothing);
    int *on_heap = calloc(1, sizeof(int));
    *on_heap = 42;
    push_front(&l, on_heap, (acceptor)&print_int, &free);
    int on_stack = 4;
    push_front(&l, &on_stack, (acceptor)&print_int, &do_nothing);
    print_list(l);
    pop_front(&l);
    pop_front(&l);
    pop_front(&l);
}

Output
4 -> 42 -> 18

This function empties the list.
There shouldn't be any memory leaks, and the list should be able to be reused.

If l is NULL, don't do anything and return.

Prototype(s)
void destroy_list(struct list **l);

Code example(s)
void do_nothing(void *n)
{
    (void)n;
}

void print_long(void *n)
{
    printf("%ld", (long)n);
}

void print_int(int *n)
{
    printf("%d", *n);
}

int main(void)
{
    struct list *l = NULL;
    push_front(&l, (void *)18, &print_long, &do_nothing);
    int *on_heap = calloc(1, sizeof(int));
    *on_heap = 42;
    push_front(&l, on_heap, (acceptor)&print_int, &free);
    int on_stack = 4;
    push_front(&l, &on_stack, (acceptor)&print_int, &do_nothing);
    print_list(l);
    destroy_list(&l);
}

Output
4 -> 42 -> 18



proficiencies/visitor.c


Information
In this part, you will be interacting with ASTs of arithmetical expressions.
You won't have to do any parsing or memory management.
You will only implement the Visitor design pattern to be able to print the AST.

The children of an ast_node are its operands, there may be 0, 1 or 2 depending on the type.

visitor.h
enum node_type
{
    // 0 operand
    NUM,

    // 1 operand
    POS,
    NEG,

    // 2 operands
    ADD,
    SUB,
    MUL,
    DIV,
    MOD,
};

struct ast_node
{
    int value;
    enum node_type type;
    struct ast_node *children;
};

typedef void(*visitor)(struct ast_node *);

Danger(s)
You MUST NOT use any if, while, for or switch!

This function should just call the visitor v on node.

Prototype(s)
void visit(struct ast_node *node, visitor v);

This function should print the ast using infix notation.
Don't forget to add a newline at the end!

Here is the format to follow, given:
- a as the first operand
- b as the second operand
- op as the operator

Output
Binary operators:
(a op b)
Unary operators:
opa
Number:
a

Prototype(s)
void print_infix(struct ast_node *node);

Code example(s)
int main(void)
{
    struct ast_node node = {
        .type = MUL,
        .children =
            (struct ast_node[]){
                {
                    .type = NUM,
                    .value = 6,
                },
                {
                    .type = NEG,
                    .children =
                        (struct ast_node[]){
                            {
                                .type = NUM,
                                .value = 7,
                            },
                        },
                },
            },
    };

    print_infix(&node);
}

Output
(6 * -7)

This function should print the ast using prefix notation.
Don't forget to add a newline at the end!

Here is the format to follow, given:
- a as the first operand
- b as the second operand
- op as the operator

Output
Binary operators:
op a b
Unary operators:
op a
Number:
a

Prototype(s)
void print_prefix(struct ast_node *node);

Code example(s)
int main(void)
{
    struct ast_node node = {
        .type = MUL,
        .children =
            (struct ast_node[]){
                {
                    .type = NUM,
                    .value = 6,
                },
                {
                    .type = NEG,
                    .children =
                        (struct ast_node[]){
                            {
                                .type = NUM,
                                .value = 7,
                            },
                        },
                },
            },
    };

    print_prefix(&node);
}

Output
* 6 - 7

This function should print the ast using suffix notation.
Don't forget to add a newline at the end!

Here is the format to follow, given:
- a as the first operand
- b as the second operand
- op as the operator

Output
Binary operators:
a b op
Unary operators:
a op
Number:
a

Prototype(s)
void print_suffix(struct ast_node *node);

Code example(s)
int main(void)
{
    struct ast_node node = {
        .type = MUL,
        .children =
            (struct ast_node[]){
                {
                    .type = NUM,
                    .value = 6,
                },
                {
                    .type = NEG,
                    .children =
                        (struct ast_node[]){
                            {
                                .type = NUM,
                                .value = 7,
                            },
                        },
                },
            },
    };

    print_suffix(&node);
}

Output
6 7 - *



[ 1.0.2 ] 2026-04-07 18:00:00
Proficiencies
  • visitor.c > print: specified adding a newline

[ 1.0.1 ] 2026-04-06 19:00:00
Guidelines
  • Guidelines > Includes: added authorized includes


This page and all subpages are for internal use at EPITA only.
The use of this document must abide by the following rules:
Copyright © 2026-2027 - EPITA